﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppGene.DataModel
{
    /// <summary>
    /// The class provide attributes information for different logical data type.
    /// </summary>
    internal class LogicalDataTypeInfo
    {
        /// <summary>
        /// Create an instance of LogicalDataTypeAttribute
        /// </summary>
        /// <param name="dataType"></param>
        public LogicalDataTypeInfo(DbType dataType)
        {
            this.DataType = dataType;
            this.DefaultLength = -1;
        }

        /// <summary>
        /// Gets or sets the native data type.
        /// </summary>
        public DbType DataType { get; private set; }

        private bool needLengthField = false;
        /// <summary>
        /// Indicates if the type need length field.
        /// </summary>
        public bool NeedLengthField
        {
            get
            {
                return needLengthField;
            }
            private set
            {
                if (value)
                {
                    HasLengthField = true;
                }
                needLengthField = value;
            }
        }

        /// <summary>
        /// Indicates if the type has length field.
        /// </summary>
        public bool HasLengthField { get; private set; }

        /// <summary>
        /// Indicates the default length. 
        /// </summary>
        public int DefaultLength { get; private set; }

        /// <summary>
        /// Indicates if the type need precision and scale fields.
        /// </summary>
        public bool NeedPrecisionScaleFields { get; private set; }

        /// <summary>
        /// Indicates if the type has precision and scale fields.
        /// </summary>
        public bool HasPrecisionScaleFields { get; private set; }

        /// <summary>
        /// Indicates the default value 
        /// </summary>
        public object DefaultValue { get; private set; }

        /// <summary>
        /// Indicates if allow null default.
        /// </summary>
        public bool AllowNull { get; private set; }

        static private Object thisLock = new Object();
        static private Dictionary<DbType, LogicalDataTypeInfo> allInstances;
        static private Dictionary<DbType, LogicalDataTypeInfo> AllInstances
        {
            get
            {
                lock (thisLock)
                {
                    if (allInstances == null)
                    {
                        InitializeAllInstances();
                    }
                }
                return allInstances;
            }
        }

        /// <summary>
        /// Get a data type attribute instance for a specific data type.
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        static public LogicalDataTypeInfo GetDataTypeAttribute(DbType dataType)
        {
            return AllInstances[dataType];
        }

        /// <summary>
        /// Initialize all instances
        /// </summary>
        static private void InitializeAllInstances()
        {
            allInstances = new Dictionary<DbType, LogicalDataTypeInfo>();

            allInstances.Add(DbType.Binary,
                new LogicalDataTypeInfo(DbType.Binary)
                {
                    NeedLengthField = true,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = null,
                    AllowNull = true
                }
                );

            allInstances.Add(DbType.Boolean,
                new LogicalDataTypeInfo(DbType.Boolean)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = 0,
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.AnsiString,
                new LogicalDataTypeInfo(DbType.AnsiString)
                {
                    NeedLengthField = true,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = "",
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.AnsiStringFixedLength,
                new LogicalDataTypeInfo(DbType.AnsiStringFixedLength)
                {
                    NeedLengthField = true,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = "",
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.Date,
                new LogicalDataTypeInfo(DbType.Date)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = null,
                    AllowNull = true
                }
                );

            allInstances.Add(DbType.DateTime,
                new LogicalDataTypeInfo(DbType.DateTime)
                {
                    NeedLengthField = false,
                    HasLengthField = true,
                    DefaultLength = 3,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = null,
                    AllowNull = true
                }
                );

            allInstances.Add(DbType.DateTimeOffset,
                new LogicalDataTypeInfo(DbType.DateTimeOffset)
                {
                    NeedLengthField = false,
                    HasLengthField = true,
                    DefaultLength = 3,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = null,
                    AllowNull = true
                }
                ); 
            
            allInstances.Add(DbType.Decimal,
                new LogicalDataTypeInfo(DbType.Decimal)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = 0,
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.Guid,
                new LogicalDataTypeInfo(DbType.Guid)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = Database.NewGuidID,
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.Int32,
                new LogicalDataTypeInfo(DbType.Int32)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = 0,
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.Int64,
                new LogicalDataTypeInfo(DbType.Int64)
                {
                    NeedLengthField = false,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = 0,
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.String,
                new LogicalDataTypeInfo(DbType.String)
                {
                    NeedLengthField = true,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = "",
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.StringFixedLength,
                new LogicalDataTypeInfo(DbType.StringFixedLength)
                {
                    NeedLengthField = true,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = "",
                    AllowNull = false
                }
                );

            allInstances.Add(DbType.Time,
                new LogicalDataTypeInfo(DbType.Time)
                {
                    NeedLengthField = false,
                    HasLengthField = true,
                    DefaultLength = 3,
                    NeedPrecisionScaleFields = false,
                    DefaultValue = "00:00:00",
                    AllowNull = false
                }
                );
        }
    }
}
